/*
  testWS.c - Linux Page Replacement Investigation
  Ben Marks, Chris Lekas

  Determine if Linux uses an working-set approximation for page
  replacement
  
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <linux/pgfltstats.h>

#include "common.h"

/*
  Iterate through a set of pages 100 times. If Linux uses working set,
  then some of these pages are bound to be in the working set.

  Parameter: n - number of pages to access in working set. Test
  values included 25, 100, 250, and 1000.
 */
void makeWS(int n) {
  
  int i;
  unsigned long first, second;

  for ( i = 0; i < 100; i ++ ) {
    my_access(10000, 10000 + n);
  }
  
}

/*
  Access the set of n pages in high to low index order, to simulate
  touching the working set again (if Linux used working set).
 */
void reaccessWS( int n ) {
  my_access( 10000 + n, 10000 );
}

/*
  Fork a process that will access 70,000 pages in memory, potentially
  evicting our working set. Parent waits for this child to finish before
  continuing. 
 */
void memStomp() {

  int pid = fork();
  if ( pid ) {
    waitpid( pid, NULL, NULL );
  }
  else {
    if ( execv( "./memStomp", NULL ) ) {
      perror("exec");
      exit(1);
    }
  }
}

/*
  Execute main test as described above to see in Linux uses a working set
  approximation.

  Command Line Arguments: argv[1] should be an integer working set size to
  use. 
 */
int main(int argc, char ** argv) {
  
  // Check parameters
  int num;
  if ( argc != 2 ) {
    printf("Usage: %s <WS Size>\n", argv[0]);
    exit(1);
  }
  num = atoi( argv[1] );
  
  // Allocate memory
  init();

  // Access num pages 100 times
  makeWS( num );

  // Anther process accesses 70,000 pages
  memStomp();
  
  // And, see how many faults we have when we access the working
  // set after another process has run. 
  struct pf_info_struct before;
  if ( pgfltstats( getpid(), PGFLTSTAT_PROC, &before ) ) {
    perror("pgfltstats");
  }

  reaccessWS( num );

  struct pf_info_struct after;
  if ( pgfltstats( getpid(), PGFLTSTAT_PROC, &after ) ) {
    perror("pgfltstats");
  }

  // Report results
  printf("WS\t%d\t%lu\t%lu\n", num, after.major - before.major,
	 after.minor - before.minor );


}
